home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Plus 1997 #1
/
Amiga Plus CD - 1997 - No. 01.iso
/
pd
/
programmierung
/
proasm
/
routines
/
startup4.r
< prev
next >
Wrap
Text File
|
1995-02-02
|
19KB
|
972 lines
;---; startup.r ;------------------------------------------------------------
*
* **** ENHANCED CLI AND WORKBENCH STARTUP WITH DETACH ****
*
* Author Stefan Walter
* Version 1.16c
* Last Revision 16.10.93
* Identifier cws_defined
* Prefix cws_ (cli and workbench startup)
* ¯ ¯ ¯
* Functions AutoDetach, ReplySync, ReplyWBMsg
*
* Flags cws_DETACH set 1 : when detaching startup
* cws_V36PLUSONLY set 1 : when tool for KS2.0 only
* cws_V37PLUSONLY set 1 : when tool for KS2.0/V37 only
* cws_CLIONLY set 1 : when tool for CLI usage only
* cws_PRI equ [pri] : if process must have priority
* [pri] otherwise the priority
* is inherited.
* cws_FPU set 1 : if FPU reset needed
* cws_EASYLIB set 1 : if libs to be opened by startup
* cws_STACKSIZE equ [stacksize] : if process must have a
* stacksize of [stacksize]
* otherwise the stacksize of the
* parent process is taken.
*
* NOTE: The startup code must be in the first code segment, along with
* the other routines it accesses.
*
;------------------------------------------------------------------------------
*
* Using this include: The main code must contain the symbols 'processname',
* 'clistartup' and 'wbstartup'. The Main program must execute 'JMP AutoDetach'.
* The child process can call ReplySync with a routine in a0. This routine gets
* executed by the parent process under permitted conditions. The child process
* *MUST* call ReplySync once with a0:=0. It waits then for a final message from
* the parent process, which is sent by this under forbid. This guarantees
* that the parent process ends in any case before the child because the memory
* belongs to the child from the moment it recieves the first messy. The parent
* process terminates under forbid.
*
;------------------------------------------------------------------------------
;------------------
ifnd cws_defined
cws_defined =1
;------------------
cws_oldbase equ __base
base cws_base
cws_base:
;------------------
;------------------------------------------------------------------------------
*
* AutoDetach Standard startup code.
*
* RESULT: If the program was started on workbench, this routine gets the
* workbench message in d0 and jumps to 'WBSTARTUP'. In case of
* CLI start, this routine autodetaches from the process and the
* new process starts at 'CLISTARTUP'. A message is sent to the
* new process to synchronize its creation with the end of the old
* process. In the message, a routine can be designed to be
* executed. The label 'PROCESSNAME' points to name.
*
* The following variables can be accessed by the customer:
*
* - cws_kick20.b -1 if V36+, else 0
* - cws_kick30.b -1 if V39+, else 0
* - cws_wbstartup.b -1 for WB, 0 for CLI
* - cws_wbmessage.l Pointer to WB message
* - cws_launchtask Pointer to parent task structure
* - cws_returnvalue Return value for parent process
*
;------------------------------------------------------------------------------
IFD cws_V37PLUSONLY
cws_V36PLUSONLY SET 1
ENDIF
;------------------
AutoDetach:
;------------------
; Get main base and save startup regs for capturing CLI.
;
\start:
pea (a4)
lea cws_base(pc),a4
movem.l d0-a6,cws_regs(a4)
move.l (sp)+,cws_regs+12*4(a4)
move.l 4.w,a6
IFD cws_FPU
;------------------
; Reset FPU.
;
\resetfpu:
MC68882
move.w 296(a6),d0
moveq #$30,d1
btst #3,d0 ;68040?
beq.s \noforty
moveq #$70,d1
\noforty:
and.w d1,d0
beq.s \findtask
fmove.l #0,fpcr
opt p=-68882
ENDIF
;------------------
; Get task and test if run from WorkBench.
;
\findtask:
IFD V37PLUSONLY
cmp.w #$25,20(a6)
ELSE
cmp.w #$24,20(a6)
ENDIF
sge cws_kick20(a4) ;remember exec version
cmp.w #39,20(a6)
sge cws_kick30(a4)
move.l $114(a6),a0
move.l a0,cws_launchtask(a4) ;remember for child
move.l $ac(a0),d6
seq cws_wbstartup(a4) ;remember in flag
bne \climode
;------------------
; Started from WB, get message.
;
\getwbmsg:
lea $5c(a0),a0
jsr -384(a6) ;WaitPort()
jsr -372(a6) ;GetMsg()
move.l d0,cws_wbmessage(a4)
;------------------
IFD cws_V36PLUSONLY
cws_REQUESTER set 1
;------------------
; Test if V36+
;
\testwb20:
IFND cws_CLIONLY
tst.b cws_kick20(a4)
bne \gowb ;okay!
bsr.s \ks20requester
bra ReplyWBMsg
ELSE
bra \clirequester
ENDIF
;------------------
; Pop up 'KS V36+ only' requester.
;
\ks20requester:
lea \maintext(pc),a1
lea \maintext2(pc),a0
move.l a0,\pt2-\maintext(a1)
lea \text2(pc),a0
move.l a0,\pt3-\maintext(a1)
bra \requester
;------------------
; Texts.
;
\maintext2:
dc.b 0,0,0,0
dc.w 10,18
dc.l 0
\pt3: dc.l 0 ;text2
dc.l 0
IFD V37PLUSONLY
\text2: dc.b "needs Kickstart V37+.",0
ELSE
\text2: dc.b "needs Kickstart V36+.",0
ENDIF
even
;------------------
ENDIF
;------------------
ifd cws_CLIONLY
cws_REQUESTER set 1
;------------------
; Pop up 'CLI only' requester.
;
\clirequester:
lea \maintext(pc),a1
lea \maintext21(pc),a0
move.l a0,\pt2-\maintext(a1)
lea \text21(pc),a0
move.l a0,\pt5-\maintext(a1)
bsr \requester
bra ReplyWBMsg
;------------------
; Texts.
;
\maintext21:
dc.b 0,0,0,0
dc.w 10,18
dc.l 0
\pt5: dc.l 0 ;text2
dc.l 0
\text21: dc.b "is for CLI usage only.",0
even
;------------------
else
;------------------
; Go to start.
; d0=WBMSG
;
\gowb: move.l d0,d7 ;store WBMessage
IFD cws_EASYLIB
bsr cws_openlibraries ;all registers unaffected
beq ReplyWBMsg
ENDIF
bsr OpenDosLib ;changes D0!!!
beq.s \nocd
move.l d0,a0 ;DosBase in A0???
move.l 32(a0),d0 ;sm_ArgList-4(a0=DosBase)
beq.s \cddone
move.l d0,a0
move.l (a0),d1 ;lock on our directory (GARBAGE)
jsr -126(a6) ;CurrentDir()
move.l d7,a0
move.l 36(a0),d0 ;sm_ArgList
beq.s \cddone
move.l d0,a0
move.l (a0),d1 ;wa_Lock
beq.s \cddone
jsr -126(a6) ;CurrentDir()
\cddone:
bsr CloseDosLib
\nocd: move.l cws_wbmessage(pc),d0
IFD cws_V36PLUSONLY
move.l cws_launchtask(a4),a3
move.l $bc(a3),cws_homedir(a4) ;HomeDir...
ENDIF
move.l (sp)+,cws_returnaddr(a4)
jsr wbstartup(pc)
move.l cws_returnaddr(pc),-(sp)
IFD cws_EASYLIB
bsr CloseLibrary
ENDIF
bra ReplyWBMsg
;------------------
endif
;------------------
ifd cws_REQUESTER
;------------------
; Open a requester.
; a1=\maintext
;
\requester:
lea \text1(pc),a0
move.l a0,\pt1-\maintext(a1)
lea \text3(pc),a0
move.l a0,\pt4-\maintext(a1)
move.l 4.w,a6
lea \intuiname(pc),a1
jsr -408(a6) ;OldOpenLibrary()
move.l d0,a6
tst.l d0
beq.s \requesterend ;no library, no requester...
suba.l a0,a0
moveq #0,d0
moveq #0,d1
moveq #30,d2
lsl.l #3,d2
moveq #64,d3
lea \maintext(pc),a1
suba.l a2,a2
lea \negativetext(pc),a3
jsr -348(a6) ;AutoRequester()
\closeintui:
move.l a6,a1
move.l 4.w,a6
jsr -414(a6) ;CloseLibrary()
\requesterend:
rts
;------------------
; IntuiText structures.
;
\maintext:
dc.b 0,0,0,0
dc.w 10,8
dc.l 0
\pt1: dc.l 0 ;text1
\pt2: dc.l 0 ;maintext2
\negativetext:
dc.b 0,0,0,0
dc.w 4,3
dc.l 0
\pt4: dc.l 0 ;text3
dc.l 0
;------------------
; Texts.
;
\text1: dc.b "The program '",gea_progname,"'",0
\text3: dc.b " Okay ",0
\intuiname: dc.b "intuition.library",0
even
;------------------
endif
;------------------
;------------------------------------------------------------------------
;- Task Detach -
;------------------------------------------------------------------------
;------------------
; To the CLI.
;
\climode:
;------------------
ifd cws_V36PLUSONLY
;------------------
; Test if V36+
;
\testcli20:
tst.b cws_kick20(a4)
beq \ks20requester
;------------------
endif
;------------------
ifd cws_DETACH
;------------------
; Okay, run from CLI or shell: Open dos.library.
;
\opendos:
bsr OpenDosLib
bne.s \getcd
move.w #fail_nodos,d0
jsr Alert(a4) ;*** failure
bne.s \opendos
bra \exit
;------------------
; Get current directory.
;
\getcd:
move.l d0,a6
moveq #0,d1
jsr -126(a6) ;CurrentDir()
move.l d0,cws_lock(a4) ;remember for duplock.
exg.l d0,d1
jsr -126(a6) ;CurrentDir()
IFD cws_V36PLUSONLY
move.l cws_launchtask(a4),a3
move.l $bc(a3),cws_homedir(a4) ;HomeDir...
ENDIF
;------------------
; Count number of segments.
;
\countsegments:
lsl.l #2,d6
\againc:moveq #0,d1
move.l d6,a3
move.l $3c(a3),d0 ;first segment
bra.s \entry
\loop:
addq.l #1,d1
move.l (a0),d0
beq.s \gotnumber
\entry:
lsl.l #2,d0
move.l d0,a0
bra.s \loop
\gotnumber:
move.w d1,cws_segnumber(a4)
;------------------
; Get enough memory for mementry for all segments.
;
\getmementrymem:
addq.l #2,d1
lsl.l #3,d1
moveq #1,d0
exg.l d0,d1
move.l 4.w,a6
jsr -198(a6) ;AllocMem()
move.l d0,cws_mementry(a4)
bne.s \launchproc
move.w #fail_nomementry,d0
jsr Alert(a4) ;*** failure
bne.s \againc
bra \closedos
;------------------
; Create new process under forbid.
;
\launchproc:
jsr -132(a6) ;Forbid()
move.l cws_launchtask(a4),a2
lea $3c(a3),a0
move.l (a0),cws_myseg(a4)
clr.l (a0) ;remove all other segments
\againp:pea \gocli-4(pc)
move.l (sp)+,d3 ;routine
lsr.l #2,d3
pea processname(a4)
move.l (sp)+,d1 ;name
moveq #0,d2
ifnd cws_PRI
move.b 9(a2),d2 ;copy pri of parent
else
moveq #cws_PRI,d2
endif
ifnd cws_STACKSIZE
move.l $34(a3),d4 ;copy stack longwords
lsl.l #2,d4 ;bytes stack
else
move.l #cws_STACKSIZE,d4 ;custom stack size
endc
bsr GetDosBase
jsr -138(a6) ;CreateProc()
;------------------
; If error occured link mementry in parent process.
;
\testprocess:
move.l d0,a2 ;process ID
move.l d0,d3 ;remember this
bne.s \insertmem
move.w #fail_noprocess,d0
jsr Alert(a4) ;*** failure
bne.s \againp
move.l cws_launchtask(a4),a2
lea $5c(a2),a2 ;link in mementry in own task
;------------------
; Insert mementry structure.
;
\insertmem:
lea -18(a2),a2 ;start of tc_mementry
move.l (a2),a1 ;remember old head
move.l cws_mementry(a4),a0
move.l a0,(a2) ;new head in list
move.l a0,4(a1) ;new pred in second node
move.l a1,(a0)+ ;next in our node
move.l a2,(a0)+ ;pred in our node
move.w #$a00,(a0)+ ;type: memory pri: 0
clr.l (a0)+ ;noname
move.w cws_segnumber(a4),d7
move.w d7,(a0)+ ;#of entries
;------------------
; Fill it out.
;
\fillout:
subq.w #1,d7
move.l cws_myseg(pc),a1
\fillloop:
add.l a1,a1
add.l a1,a1
subq.l #4,a1
move.l a1,(a0)+ ;address
move.l (a1)+,(a0)+ ;length
move.l (a1)+,a1
dbra d7,\fillloop
;-------------------
; Now, all went fine(d3<>0)?.
;
\didwe:
tst.l d3
beq \noforbid
;------------------
; Send message to child. Send first message to process port, others
; to custom port.
;
\sendmsg:
st.b cws_sync(a4) ;we begin...
move.l d3,cws_portptr(a4)
\sendmsgloop:
move.l cws_launchtask(pc),a2
lea $5c(a2),a2
move.l cws_portptr(pc),a0
lea cws_messy(pc),a1
move.l a2,14(a1) ;replyport...
move.l 4.w,a6
jsr -366(a6) ;PutMsg()
;------------------
; Wait for reply.
;
\wait:
move.l a2,a0
jsr -384(a6) ;WaitPort()
move.l a2,a0
jsr -372(a6) ;GetMsg()
move.l d0,a0
lea cws_messy(pc),a1
move.l 20(a0),d0
beq.s \sendend
;------------------
; Permit, call routine, forbid and wait for nilroutine messy.
;
\call:
pea \rts(pc)
move.l d0,-(sp)
jmp -138(a6) ;Permit() and then routine
\rts:
jsr -132(a6)
bra \sendmsgloop
;------------------
; Send final message to child.
;
\sendend:
move.l cws_portptr(pc),a0
lea cws_messy(pc),a1
jsr -366(a6) ;PutMsg()
;------------------
; Prepare to Permit().
;
\noforbid:
pea -138(a6) ;Permit()
;------------------
; Close dos.library.
;
\closedos:
bsr CloseDosLib
;------------------
; Leave this code.
;
\exit:
movem.l cws_regs(a4),d0-a5 ;a6=[4] for permit()!
move.l cws_returnvalue(pc),d0 ;returnvalue
rts
;--------------------------------------------------------------------
; Patch return address, handle locks and go to cli (foreign task territory).
;
\makebcpl:
align.l ;because of BCPL
dc.l 0,0 ;some monitors crash when this is not here
\gocli: lea cws_base(pc),a4
lea cws_returnaddr(pc),a0
move.l (sp)+,(a0) ;remember real return
move.l 4.w,a6
move.l $114(a6),a0
move.l $80(a0),d0
beq.s \openport
lsl.l #2,d0
move.l d0,a0
move.l cws_myseg(pc),$c(a0) ;copy segment list.
;------------------
; Open new port and fail if not.
;
\openport:
lea cws_port(pc),a0
bsr MakePort
bne.s \gotport
move.w #fail_nostartp,d0
jsr Alert(a4) ;*** failure
bne.s \openport
\bad: suba.l a0,a0
bsr ReplySync
bra \fexit
\gotport:
lea cws_dummy(pc),a0
bsr ReplySync
;------------------
; Change directory to the new lock.
;
\changedir:
bsr OpenDosLib ;the child will free it when ending
move.l d0,a6 ;it exists, parent has it still open
move.l cws_lock(pc),d1
beq.s \lockduped
jsr -96(a6) ;DupLock()
move.l d0,d1
move.l d0,cws_lock(a4)
move.l d0,cws_currentdir(a4)
\lockduped:
jsr -126(a6) ;CurrentDir() DOES NOT USE MSGS!
IFD cws_V36PLUSONLY
move.l cws_homedir(pc),d1
beq.s \nghd
jsr -96(a6) ;DupLock()
move.l d0,cws_homedir(a4)
move.l 4.w,a6
move.l $114(a6),a4
move.l d0,$bc(a4)
\nghd: ENDIF
IFD cws_EASYLIB
bsr cws_openlibraries
bne.s \go
suba.l a0,a0
bsr ReplySync
bra.s \unlock
ENDIF
\go: movem.l cws_regs(pc),d0-a6
jsr clistartup(pc) ;GO!
IFD cws_EASYLIB
bsr CloseLibrary
ENDIF
;------------------
; Unlock DupLock()ed struct
;
\unlock:
movem.l d0-a6,-(sp)
IFD cws_V36PLUSONLY
move.l cws_homedir(pc),d1
beq.s \nhd
bsr GetDosBase
jsr -90(a6) ;Unlock()
move.l 4.w,a6
move.l $114(a6),a4
clr.l $bc(a4)
\nhd: ENDIF
move.l cws_lock(pc),d1
beq.s \nlock
bsr GetDosBase
jsr -90(a6) ;Unlock()
moveq #0,d1
jsr -126(a6) ;ChangeDir()
\nlock: bsr CloseDosLib
movem.l (sp)+,d0-a6
\fexit: move.l cws_returnaddr(pc),-(sp)
rts
;------------------
;------------------------------------------------------------------------------
*
* ReplySync Reply to startup message and set routine.
*
* INPUT: a0 Address of routine to be called
*
* RESULT: Waits for startup message and replies to it, setting
* the routine field to d0. Then it waits again for a
* message. This routine can be called without concideration
* of WB or CLI start or if ReplySync already terminated.
*
;------------------------------------------------------------------------------
;------------------
ReplySync:
;------------------
; Get task address.
;
\start:
movem.l d0-a6,-(sp)
lea cws_wbstartup(pc),a3
tst.b (a3) ;from WB?
bne.s \exit
move.b cws_sync(pc),d0 ;done yet?
beq.s \exit
move.l a0,a3
move.l 4.w,a6
move.l cws_portptr(pc),a2
;------------------
; Wait for messy and test if it is 'messy'.
;
\wait:
move.l a2,a0
jsr -384(a6) ;WaitPort()
move.l a2,a0
jsr -372(a6) ;GetMsg()
tst.l d0
beq.s \wait
move.l d0,a1
lea cws_messy(pc),a0
cmp.l a0,a1
bne.s \wait
pea cws_dummy(pc)
cmp.l (sp)+,a3
bne.s \nodummy
lea cws_portptr(pc),a0
pea cws_port(pc)
move.l (sp)+,(a0) ;set new port to use.
\nodummy:
move.l a3,20(a1)
jsr -378(a6) ;ReplyMsg()
;------------------
; Now wait again, either for next messy or for final messy.
; If final messy, get it so DOS can then use port for IO.
;
\again
move.l cws_portptr(pc),a2
move.l a2,a0
jsr -384(a6) ;WaitPort()
move.l a3,d0
bne.s \exit
move.l a2,a0
jsr -372(a6) ;GetMsg()
lea cws_port(pc),a0
bsr UnMakePort
lea cws_sync(pc),a0
clr.b (a0)
;------------------
; Exit.
;
\exit:
movem.l (sp)+,d0-a6
rts
;------------------
;--------------------------------------------------------------------
;------------------
; Data only used by detaching startup.
;
;------------------
include alert.r
include ports.r
;------------------
AddAlert_ fail_nodos,"Unable to open dos.library"
AddAlert_ fail_nomementry,"No memory for mementry struct"
AddAlert_ fail_noprocess,"Unable to create process"
AddAlert_ fail_nostartp,"Unable to create port"
;------------------
; Startup message.
;
cws_messy: dc.l 0,0
dc.b 05,0
dc.l 0
dc.l 0 ;replyport
dc.w 24 ;length
cws_routine: dc.l 0 ;routine to be called
cws_dummy: rts ;dummy routine for port switch
;------------------
; Second port.
;
cws_port:
ds.b 10,0
dc.l 0 ;no name
dc.b 0,0 ;flag,sigbit
dc.l 0 ;sigtask
ds.b 14,0 ;MSG list
;------------------
cws_portptr: dc.l 0
cws_myseg: dc.l 0
cws_mementry: dc.l 0
cws_lock: dc.l 0
cws_currentdir: dc.l 0
cws_segnumber: dc.w 0
cws_sync: dc.b 0
dc.b 0
cws_returnvalue:dc.l 0
;------------------
;--------------------------------------------------------------------
;------------------
else
;------------------
; Simply go to start.
;
\gocli:
IFD cws_EASYLIB
moveq #0,d0
bsr cws_openlibraries
beq.s \nogo
ENDIF
IFD cws_V36PLUSONLY
move.l cws_launchtask(a4),a3
move.l $bc(a3),cws_homedir(a4) ;HomeDir...
ENDIF
move.l (sp)+,cws_returnaddr(a4)
movem.l cws_regs(a4),d0-a6
jsr clistartup(pc)
move.l cws_returnaddr(pc),-(sp)
IFD cws_EASYLIB
bsr CloseLibrary
ENDIF
\nogo: rts
;------------------
endif
;------------------
;------------------------------------------------------------------------------
*
* ReplyWBMsg Reply to workbench message and go forbid.
*
* RESULT: Replies to cws_wbmessage and calls Forbid() because the WB
* imediately frees the process memory. This routine can be
* called without concideration of WB or CLI start.
*
;------------------------------------------------------------------------------
;------------------
ReplyWBMsg:
;------------------
; Start.
;
\start:
movem.l d0-a6,-(sp)
lea cws_wbstartup(pc),a0
tst.b (a0) ;from CLI?
beq.s \exit
lea cws_wbmessage(pc),a1
move.l (a1),d0
beq.s \exit
clr.l (a1)
move.l d0,a1
move.l 4.w,a6
jsr -132(a6) ;ReplyMsg frees segments!
jsr -378(a6) ;ReplyMsg()
;------------------
; End.
;
\exit:
movem.l (sp)+,d0-a6
rts
;------------------
; Data always used.
;
cws_wbstartup: dc.b 0 ;-1 for WB, 0 for CLI
cws_kick20: dc.b 0 ;-1 for 2.0+, 0 for 1.2/1.3
cws_kick30: dc.b 0 ;-1 for 3.0+, 0 for lower
dc.b 0
cws_launchtask: dc.l 0
cws_wbmessage: dc.l 0
cws_returnaddr: dc.l 0
cws_regs: ds.l 15,0
IFD cws_V36PLUSONLY
cws_homedir: dc.l 0
ENDIF
;------------------
include doslib.r
;------------------
;--------------------------------------------------------------------
IFD cws_EASYLIB
;------------------
ely_NOALERT SET 1
include easylibrary.r
include alert.r
cws_alerttext:
AddAlert_ fail_nolibs,"Could not open "
;------------------
; Open libs wanted and display alert if one fails!
;
; ccr=>EQ if failed
;
cws_openlibraries:
movem.l d0-a6,-(sp)
\again: bsr OpenLibrary
tst.l d0
bne.s \done
bsr CloseLibrary
lea cws_alerttext+15(pc),a1
\loop: move.b (a0)+,(a1)+
bne.s \loop
move.w #fail_nolibs,d0
bsr Alert
bne.s \again
\done: movem.l (sp)+,d0-a6
rts
;------------------
ENDIF
;--------------------------------------------------------------------
;------------------
base cws_oldbase
;------------------
endif
end